﻿using Consul;
using Newtonsoft.Json;

namespace Zore.App.Core.Consul
{
    public static class CallService
    {
        /// <summary>
        /// 用于访问对应的Consul已注册的服务
        /// </summary>
        /// <param name="callParams"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static async Task<string> Call(CallParams callParams)
        {
            var consulClient = new ConsulClient();
            var services = await consulClient.Agent.Services();
            if (services.Response.Keys.Any(s => s.Contains(callParams.ServiceName)))
            {
                var service = services.Response.FirstOrDefault(s => s.Key.Contains(callParams.ServiceName)).Value;
                var host = service.Address;
                var port = service.Port;
                var httpClient = new HttpClient();
                var serviceUrl = $"http://{host}:{port}/{callParams.Api}";
                HttpResponseMessage response = null;
                switch (callParams.Method.Method)
                {
                    case "GET":
                        if (callParams.Args.Any())
                        {
                            var url = serviceUrl + $"?{string.Join("&", callParams.Args.Select(a => $"{a.Key}={a.Value}"))}";
                            response = await httpClient.GetAsync(url);
                        }
                        else
                        {
                            response = await httpClient.GetAsync(serviceUrl);
                        }

                        break;
                    case "POST":
                        response = await httpClient.PostAsync(serviceUrl, new StringContent(JsonConvert.SerializeObject(callParams.Args)));
                        break;
                    case "PUT":
                        response = await httpClient.PutAsync(serviceUrl, new StringContent(JsonConvert.SerializeObject(callParams.Args)));
                        break;
                    case "DELETE":
                        response = await httpClient.DeleteAsync(serviceUrl);
                        break;
                    default:
                        throw new Exception($"Invalid method {callParams.Method}");
                }
                if (!response.IsSuccessStatusCode)
                {
                    throw new Exception($"Failed to call service {callParams.ServiceName}");
                }
                var content = await response.Content.ReadAsStringAsync();
                return content;
            }
            else
            {
                throw new Exception($"Service {callParams.ServiceName} not found");
            }
        }
    }

    public class CallParams
    {
        public string ServiceName { get; set; }
        public string Api { get; set; }
        public HttpMethod Method { get; set; }
        public List<CallParamItem> Args { get; set; } = new List<CallParamItem>();
    }

    public class CallParamItem
    {
        public string Key { get; set; }
        public object Value { get; set; }
    }
}
